﻿using BankTransfer.Bank.Domain.Domain.Entity;
using BankTransfer.Bank.Domain.Domain.Service;
using BankTransfer.Bank.Domain.Extarnal;
using BankTransfer.Bank.Domain.Messaging;
using BankTransfer.Bank.Domain.Repository;
using BankTransfer.Bank.Types.Enum;
using BankTransfer.Bank.Types.Types;

namespace BankTransfer.Bank.Application.Impl
{
    public class TransferServiceImpl : ITransferService
    {
        // 通过 Entity、Domain Primitive 和 Domain Service 封装所有的业务逻辑
        private readonly IExchangeRateService exchangeRateService;
        private readonly IAccountRepository accountRepository;
        private readonly IAuditMessageProducer auditMessageProducer;
        private readonly IAccountTransferService accountTransferService;

        public TransferServiceImpl(IExchangeRateService exchangeRateService
            , IAccountRepository accountRepository
            , IAuditMessageProducer auditMessageProducer
            , IAccountTransferService accountTransferService)
        {
            this.exchangeRateService = exchangeRateService;
            this.accountRepository = accountRepository;
            this.auditMessageProducer = auditMessageProducer;
            this.accountTransferService = accountTransferService;
        }

        public bool Transfer(long sourceUserId, string targetAccountNumber, decimal targetAmount, Currency targetCurrency)
        {
            Money targetMoney = new Money(targetAmount, targetCurrency);
            Account sourceAccount = accountRepository.Find(new UserId(sourceUserId));
            Account targetAccount = accountRepository.Find(new AccountNumber(targetAccountNumber));
            ExchangeRate exchangeRate = exchangeRateService.GetExchangeRate(sourceAccount.Currency, targetMoney.Currency);

            // 业务逻辑
            accountTransferService.Transfer(sourceAccount, targetAccount, targetMoney, exchangeRate);

            // 保存数据(考虑事务略)
            accountRepository.Save(sourceAccount);
            accountRepository.Save(targetAccount);

            // 发送审计消息
            AuditMessage message = new AuditMessage(sourceAccount.UserId, sourceAccount.AccountNumber, targetAccount.AccountNumber, targetMoney);
            auditMessageProducer.Send(message);
            return true; 
        }
    }
}